﻿using Lyo.Comm;
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace FuckVmp.MemoryPE
{
    public class PEInfo
    {
        #region const
        public const uint MEM_COMMIT = 0x00001000;
        public const uint MEM_RESERVE = 0x00002000;
        public const uint MEM_DECOMMIT = 0x00004000;
        public const uint MEM_RELEASE = 0x00008000;
        public const uint PAGE_NOACCESS = 0x01;
        public const uint PAGE_READONLY = 0x02;
        public const uint PAGE_READWRITE = 0x04;
        public const uint PAGE_WRITECOPY = 0x08;
        public const uint PAGE_EXECUTE = 0x10;
        public const uint PAGE_EXECUTE_READ = 0x20;
        public const uint PAGE_EXECUTE_READWRITE = 0x40;
        public const uint PAGE_EXECUTE_WRITECOPY = 0x80;
        public const uint PAGE_NOCACHE = 0x200;
        public const ushort IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
        public const uint IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
        public const uint IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
        public const uint IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
        public const uint IMAGE_DIRECTORY_ENTRY_BASERELOC = 5;
        public const uint IMAGE_DIRECTORY_ENTRY_TLS = 9;
        public const ulong IMAGE_ORDINAL_FLAG64 = 0x8000000000000000;
        public const uint IMAGE_ORDINAL_FLAG32 = 0x80000000;

        /// <summary>
        /// 表示 section 可执行 
        /// </summary>
        public const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000;
        public const uint IMAGE_SCN_MEM_READ = 0x40000000;
        public const uint IMAGE_SCN_MEM_WRITE = 0x80000000;
        public const uint DLL_PROCESS_ATTACH = 1;
        public const uint DLL_PROCESS_DETACH = 0;
        public const uint IMAGE_REL_BASED_ABSOLUTE = 0;
        public const uint IMAGE_REL_BASED_HIGHLOW = 3;
        public const uint IMAGE_REL_BASED_DIR64 = 10;
        public const ushort IMAGE_DOS_SIGNATURE = 0x5A4D;
        public const uint IMAGE_NT_SIGNATURE = 0x00004550;
        public const ushort IMAGE_FILE_MACHINE_I386 = 0x014c;
        public const ushort IMAGE_FILE_MACHINE_AMD64 = 0x8664;
        public const uint IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
        public const uint IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
        public const uint IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
        public const uint IMAGE_SCN_MEM_NOT_CACHED = 0x04000000;
        public const uint IMAGE_FILE_DLL = 0x2000;
        #endregion

        #region struct
        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_DOS_HEADER
        {
            public ushort e_magic;
            public ushort e_cblp;
            public ushort e_cp;
            public ushort e_crlc;
            public ushort e_cparhdr;
            public ushort e_minalloc;
            public ushort e_maxalloc;
            public ushort e_ss;
            public ushort e_sp;
            public ushort e_csum;
            public ushort e_ip;
            public ushort e_cs;
            public ushort e_lfarlc;
            public ushort e_ovno;
            //public fixed ushort e_res1[4];

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public ushort[] e_res1;
            public ushort e_oemid;
            public ushort e_oeminfo;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
            //public fixed ushort e_res2[10];
            public ushort[] e_res2;
            public uint e_lfanew;
            public static readonly uint UnmanagedSize = (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_NT_HEADERS32
        {
            public uint Signature;
            public IMAGE_FILE_HEADER FileHeader;
            public IMAGE_OPTIONAL_HEADER32 OptionalHeader;
            public static readonly uint UnmanagedSize = (uint)Marshal.SizeOf(typeof(IMAGE_NT_HEADERS32));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_NT_HEADERS64
        {
            public uint Signature;
            public IMAGE_FILE_HEADER FileHeader;
            public IMAGE_OPTIONAL_HEADER64 OptionalHeader;
            public static readonly uint UnmanagedSize = (uint)Marshal.SizeOf(typeof(IMAGE_NT_HEADERS64));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_FILE_HEADER
        {
            public ushort Machine;
            public ushort NumberOfSections;
            public uint TimeDateStamp;
            public uint PointerToSymbolTable;
            public uint NumberOfSymbols;
            public ushort SizeOfOptionalHeader;
            public ushort Characteristics;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_OPTIONAL_HEADER32
        {
            public ushort Magic;
            public byte MajorLinkerVersion;
            public byte MinorLinkerVersion;
            public uint SizeOfCode;
            public uint SizeOfInitializedData;
            public uint SizeOfUninitializedData;
            public uint AddressOfEntryPoint;
            public uint BaseOfCode;
            public uint BaseOfData;
            public uint ImageBase;
            public uint SectionAlignment;
            public uint FileAlignment;
            public ushort MajorOperatingSystemVersion;
            public ushort MinorOperatingSystemVersion;
            public ushort MajorImageVersion;
            public ushort MinorImageVersion;
            public ushort MajorSubsystemVersion;
            public ushort MinorSubsystemVersion;
            public uint Win32VersionValue;
            public uint SizeOfImage;
            public uint SizeOfHeaders;
            public uint CheckSum;
            public ushort Subsystem;
            public ushort DllCharacteristics;
            public uint SizeOfStackReserve;
            public uint SizeOfStackCommit;
            public uint SizeOfHeapReserve;
            public uint SizeOfHeapCommit;
            public uint LoaderFlags;
            public uint NumberOfRvaAndSizes;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
            //public fixed ulong DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
            public ulong[] DataDirectory;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_OPTIONAL_HEADER64
        {
            public ushort Magic;
            public byte MajorLinkerVersion;
            public byte MinorLinkerVersion;
            public uint SizeOfCode;
            public uint SizeOfInitializedData;
            public uint SizeOfUninitializedData;
            public uint AddressOfEntryPoint;
            public uint BaseOfCode;
            public ulong ImageBase;
            public uint SectionAlignment;
            public uint FileAlignment;
            public ushort MajorOperatingSystemVersion;
            public ushort MinorOperatingSystemVersion;
            public ushort MajorImageVersion;
            public ushort MinorImageVersion;
            public ushort MajorSubsystemVersion;
            public ushort MinorSubsystemVersion;
            public uint Win32VersionValue;
            public uint SizeOfImage;
            public uint SizeOfHeaders;
            public uint CheckSum;
            public ushort Subsystem;
            public ushort DllCharacteristics;
            public ulong SizeOfStackReserve;
            public ulong SizeOfStackCommit;
            public ulong SizeOfHeapReserve;
            public ulong SizeOfHeapCommit;
            public uint LoaderFlags;
            public uint NumberOfRvaAndSizes;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
            //public fixed ulong DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
            public ulong[] DataDirectory;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_DATA_DIRECTORY
        {
            public uint VirtualAddress;
            public uint Size;
        }

        [StructLayout(LayoutKind.Sequential)]
        public class IMAGE_SECTION_HEADER
        {

            [Flags]
            public enum CharacteristicsInfo
            {
                // 文件中不存在重定位信息
                IMAGE_FILE_RELOCS_STRIPPED = 1,
                // 文件是可执行的
                IMAGE_FILE_EXECUTABLE_IMAGE = 2,
                // 不存在行信息
                IMAGE_FILE_LINE_NUMS_STRIPPED = 4,
                //不存在符号信息
                IMAGE_FILE_LOCAL_SYMS_STRIPPED = 8,

                IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x10,

                IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x20,
                //小尾方式
                IMAGE_FILE_BYTES_REVERSED_LO = 0x0080,
                // 只在３２位平台运行
                IMAGE_FILE_32BIT_MACHINE = 0x0100,
                //不包含调试信息
                IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
                // 不能从可移动盘运行
                IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400,
                // 不能从网络运行
                IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800,
                // 系统文件。不能直接运行
                IMAGE_FILE_SYSTEM = 0x1000,
                // 13 ＤＬＬ文件
                IMAGE_FILE_DLL = 0x2000,
                // 14 文件不能在多处理器上运行
                IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000,
                // 15
                IMAGE_FILE_BYTES_REVERSED_HI = 0x8000
            }



            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            //public fixed byte Name[8];
            public byte[] Name;

            public string name
            {
                get => Encoding.ASCII.GetString(Name).Replace("\0", "");
            }


            public uint PhysicalAddress;
            public uint VirtualAddress;
            public uint SizeOfRawData;
            public uint PointerToRawData;
            public uint PointerToRelocations;
            public uint PointerToLinenumbers;
            public ushort NumberOfRelocations;
            public ushort NumberOfLinenumbers;
            public uint Characteristics;

        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_BASE_RELOCATION
        {
            public uint VirtualAddress;
            public uint SizeOfBlock;
            public static readonly uint UnmanagedSize = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_IMPORT_DESCRIPTOR
        {
            public uint OriginalFirstThunk;
            public uint TimeDateStamp;
            public uint ForwarderChain;
            public uint Name;
            public uint FirstThunk;
            public static readonly uint UnmanagedSize = (uint)Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_EXPORT_DIRECTORY
        {
            public uint Characteristics;
            public uint TimeDateStamp;
            public ushort MajorVersion;
            public ushort MinorVersion;
            public uint Name;
            public uint Base;
            public uint NumberOfFunctions;
            public uint NumberOfNames;
            public uint AddressOfFunctions;
            public uint AddressOfNames;
            public uint AddressOfNameOrdinals;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_IMPORT_BY_NAME
        {
            public ushort Hint;
            //public fixed byte Name[1];
            public byte Name;
        }

        //[StructLayout(LayoutKind.Sequential)]
        //public struct SYSTEM_INFO {
        //	public ushort wProcessorArchitecture;
        //	public ushort wReserved;
        //	public uint dwPageSize;
        //	public void* lpMinimumApplicationAddress;
        //	public void* lpMaximumApplicationAddress;
        //	public void* dwActiveProcessorMask;
        //	public uint dwNumberOfProcessors;
        //	public uint dwProcessorType;
        //	public uint dwAllocationGranularity;
        //	public ushort wProcessorLevel;
        //	public ushort wProcessorRevision;
        //};

        //[StructLayout(LayoutKind.Sequential)]
        //public struct IMAGE_TLS_DIRECTORY {
        //	public void* StartAddressOfRawData;
        //	public void* EndAddressOfRawData;
        //	public void* AddressOfIndex;
        //	public void* AddressOfCallBacks;
        //	public void* SizeOfZeroFill;
        //	public uint Characteristics;
        //}

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_RESOURCE_DIRECTORY_ENTRY
        {
            public uint Name;
            public uint OffsetToData;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_RESOURCE_DIRECTORY
        {
            public uint Characteristics;
            public uint TimeDateStamp;
            public ushort MajorVersion;
            public ushort MinorVersion;
            public ushort NumberOfNamedEntries;
            public ushort NumberOfIdEntries;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_RESOURCE_DATA_ENTRY
        {
            public uint OffsetToData;
            public uint Size;
            public uint CodePage;
            public uint Reserved;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_RESOURCE_DIR_STRING_U
        {
            public ushort Length;
            //public fixed char NameString[1];
            public char NameString;
        }
        #endregion





        #region 数据 
        public IMAGE_DOS_HEADER dosH;
        public IMAGE_NT_HEADERS32 nt_header;

        public bool Is64 { get; private set; }

        /// <summary> 启用了重定位 </summary>
        public bool IsRelative { get; private set; }

        public IMAGE_SECTION_HEADER[] Sections { get; internal set; } = null;

        #endregion


        public static PEInfo Load(ulong addr, byte[] data)
        {

            PEInfo info = new PEInfo();

            info.dosH = StructHelper.FromBytes<IMAGE_DOS_HEADER>(data);

            if (info.dosH.e_magic != IMAGE_DOS_SIGNATURE)
                return null;

            int next_off = (int)info.dosH.e_lfanew;


            info.nt_header = StructHelper.FromBytes<IMAGE_NT_HEADERS32>(data, (int)next_off);

            if (info.nt_header.Signature != IMAGE_NT_SIGNATURE)
                return null;

            // x86  pe 文件 
            if (info.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
            {
                info.Is64 = false;
                IMAGE_NT_HEADERS32 ntH = StructHelper.FromBytes<IMAGE_NT_HEADERS32>(data, (int)next_off);


                next_off += Marshal.SizeOf(ntH);


                // Section 位于 紧接在  nt_header 后面 

                info.Sections = (IMAGE_SECTION_HEADER[])StructHelper.ArrFromBytes<IMAGE_SECTION_HEADER>(data, (int)next_off, ntH.FileHeader.NumberOfSections);


            }

            // x64  pe 文件 
            else
            {
                info.Is64 = true;

                IMAGE_NT_HEADERS64 ntH = StructHelper.FromBytes<IMAGE_NT_HEADERS64>(data, (int)next_off);


                next_off += Marshal.SizeOf(ntH);


                // Section 位于 紧接在  nt_header 后面 

                info.Sections = (IMAGE_SECTION_HEADER[])StructHelper.ArrFromBytes<IMAGE_SECTION_HEADER>(data, (int)next_off, ntH.FileHeader.NumberOfSections);


            }


            info.IsRelative = (info.nt_header.OptionalHeader.DllCharacteristics & 0x40) > 0;



            return info;
        }

    }
}
